home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_include / ASM-SPAR.{_6 / BITOPS.H < prev    next >
C/C++ Source or Header  |  1999-09-17  |  9KB  |  409 lines

  1. /* $Id: bitops.h,v 1.54 1998/09/21 05:07:34 jj Exp $
  2.  * bitops.h: Bit string operations on the Sparc.
  3.  *
  4.  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
  5.  * Copyright 1996 Eddie C. Dost   (ecd@skynet.be)
  6.  */
  7.  
  8. #ifndef _SPARC_BITOPS_H
  9. #define _SPARC_BITOPS_H
  10.  
  11. #include <linux/kernel.h>
  12. #include <asm/byteorder.h>
  13.  
  14. #ifndef __KERNEL__
  15.  
  16. /* User mode bitops, defined here for convenience. Note: these are not
  17.  * atomic, so packages like nthreads should do some locking around these
  18.  * themself.
  19.  */
  20.  
  21. #define __SMPVOL
  22.  
  23. extern __inline__ unsigned long set_bit(unsigned long nr, void *addr)
  24. {
  25.     int mask;
  26.     unsigned long *ADDR = (unsigned long *) addr;
  27.  
  28.     ADDR += nr >> 5;
  29.     mask = 1 << (nr & 31);
  30.     __asm__ __volatile__("
  31.     ld    [%0], %%g3
  32.     or    %%g3, %2, %%g2
  33.     st    %%g2, [%0]
  34.     and    %%g3, %2, %0
  35.     "
  36.     : "=&r" (ADDR)
  37.     : "0" (ADDR), "r" (mask)
  38.     : "g2", "g3");
  39.  
  40.     return (unsigned long) ADDR;
  41. }
  42.  
  43. extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
  44. {
  45.     int mask;
  46.     unsigned long *ADDR = (unsigned long *) addr;
  47.  
  48.     ADDR += nr >> 5;
  49.     mask = 1 << (nr & 31);
  50.     __asm__ __volatile__("
  51.     ld    [%0], %%g3
  52.     andn    %%g3, %2, %%g2
  53.     st    %%g2, [%0]
  54.     and    %%g3, %2, %0
  55.     "
  56.     : "=&r" (ADDR)
  57.     : "0" (ADDR), "r" (mask)
  58.     : "g2", "g3");
  59.  
  60.     return (unsigned long) ADDR;
  61. }
  62.  
  63. extern __inline__ void change_bit(unsigned long nr, void *addr)
  64. {
  65.     int mask;
  66.     unsigned long *ADDR = (unsigned long *) addr;
  67.  
  68.     ADDR += nr >> 5;
  69.     mask = 1 << (nr & 31);
  70.     __asm__ __volatile__("
  71.     ld    [%0], %%g3
  72.     xor    %%g3, %2, %%g2
  73.     st    %%g2, [%0]
  74.     and    %%g3, %2, %0
  75.     "
  76.     : "=&r" (ADDR)
  77.     : "0" (ADDR), "r" (mask)
  78.     : "g2", "g3");
  79. }
  80.  
  81. #else /* __KERNEL__ */
  82.  
  83. #include <asm/system.h>
  84.  
  85. #ifdef __SMP__
  86. #define __SMPVOL volatile
  87. #else
  88. #define __SMPVOL
  89. #endif
  90.  
  91. /* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
  92.  * is in the highest of the four bytes and bit '31' is the high bit
  93.  * within the first byte. Sparc is BIG-Endian. Unless noted otherwise
  94.  * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
  95.  */
  96.  
  97. extern __inline__ unsigned long test_and_set_bit(unsigned long nr, __SMPVOL void *addr)
  98. {
  99.     register unsigned long mask asm("g2");
  100.     register unsigned long *ADDR asm("g1");
  101.     ADDR = ((unsigned long *) addr) + (nr >> 5);
  102.     mask = 1 << (nr & 31);
  103.     __asm__ __volatile__("
  104.     mov    %%o7, %%g4
  105.     call    ___set_bit
  106.      add    %%o7, 8, %%o7
  107. "    : "=&r" (mask)
  108.     : "0" (mask), "r" (ADDR)
  109.     : "g3", "g4", "g5", "g7", "cc");
  110.  
  111.     return mask != 0;
  112. }
  113.  
  114. extern __inline__ void set_bit(unsigned long nr, __SMPVOL void *addr)
  115. {
  116.     (void) test_and_set_bit(nr, addr);
  117. }
  118.  
  119. extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, __SMPVOL void *addr)
  120. {
  121.     register unsigned long mask asm("g2");
  122.     register unsigned long *ADDR asm("g1");
  123.  
  124.     ADDR = ((unsigned long *) addr) + (nr >> 5);
  125.     mask = 1 << (nr & 31);
  126.     __asm__ __volatile__("
  127.     mov    %%o7, %%g4
  128.     call    ___clear_bit
  129.      add    %%o7, 8, %%o7
  130. "    : "=&r" (mask)
  131.     : "0" (mask), "r" (ADDR)
  132.     : "g3", "g4", "g5", "g7", "cc");
  133.  
  134.     return mask != 0;
  135. }
  136.  
  137. extern __inline__ void clear_bit(unsigned long nr, __SMPVOL void *addr)
  138. {
  139.     (void) test_and_clear_bit(nr, addr);
  140. }
  141.  
  142. extern __inline__ unsigned long test_and_change_bit(unsigned long nr, __SMPVOL void *addr)
  143. {
  144.     register unsigned long mask asm("g2");
  145.     register unsigned long *ADDR asm("g1");
  146.  
  147.     ADDR = ((unsigned long *) addr) + (nr >> 5);
  148.     mask = 1 << (nr & 31);
  149.     __asm__ __volatile__("
  150.     mov    %%o7, %%g4
  151.     call    ___change_bit
  152.      add    %%o7, 8, %%o7
  153. "    : "=&r" (mask)
  154.     : "0" (mask), "r" (ADDR)
  155.     : "g3", "g4", "g5", "g7", "cc");
  156.  
  157.     return mask != 0;
  158. }
  159.  
  160. extern __inline__ void change_bit(unsigned long nr, __SMPVOL void *addr)
  161. {
  162.     (void) test_and_change_bit(nr, addr);
  163. }
  164.  
  165. #endif /* __KERNEL__ */
  166.  
  167. /* The following routine need not be atomic. */
  168. extern __inline__ unsigned long test_bit(int nr, __const__ __SMPVOL void *addr)
  169. {
  170.     return 1UL & (((__const__ unsigned int *) addr)[nr >> 5] >> (nr & 31));
  171. }
  172.  
  173. /* The easy/cheese version for now. */
  174. extern __inline__ unsigned long ffz(unsigned long word)
  175. {
  176.     unsigned long result = 0;
  177.  
  178.     while(word & 1) {
  179.         result++;
  180.         word >>= 1;
  181.     }
  182.     return result;
  183. }
  184.  
  185. #ifdef __KERNEL__
  186.  
  187. /*
  188.  * ffs: find first bit set. This is defined the same way as
  189.  * the libc and compiler builtin ffs routines, therefore
  190.  * differs in spirit from the above ffz (man ffs).
  191.  */
  192.  
  193. #define ffs(x) generic_ffs(x)
  194.  
  195. /*
  196.  * hweightN: returns the hamming weight (i.e. the number
  197.  * of bits set) of a N-bit word
  198.  */
  199.  
  200. #define hweight32(x) generic_hweight32(x)
  201. #define hweight16(x) generic_hweight16(x)
  202. #define hweight8(x) generic_hweight8(x)
  203.  
  204. #endif /* __KERNEL__ */
  205.  
  206. /* find_next_zero_bit() finds the first zero bit in a bit string of length
  207.  * 'size' bits, starting the search at bit 'offset'. This is largely based
  208.  * on Linus's ALPHA routines, which are pretty portable BTW.
  209.  */
  210.  
  211. extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
  212. {
  213.     unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
  214.     unsigned long result = offset & ~31UL;
  215.     unsigned long tmp;
  216.  
  217.     if (offset >= size)
  218.         return size;
  219.     size -= result;
  220.     offset &= 31UL;
  221.     if (offset) {
  222.         tmp = *(p++);
  223.         tmp |= ~0UL >> (32-offset);
  224.         if (size < 32)
  225.             goto found_first;
  226.         if (~tmp)
  227.             goto found_middle;
  228.         size -= 32;
  229.         result += 32;
  230.     }
  231.     while (size & ~31UL) {
  232.         if (~(tmp = *(p++)))
  233.             goto found_middle;
  234.         result += 32;
  235.         size -= 32;
  236.     }
  237.     if (!size)
  238.         return result;
  239.     tmp = *p;
  240.  
  241. found_first:
  242.     tmp |= ~0UL << size;
  243. found_middle:
  244.     return result + ffz(tmp);
  245. }
  246.  
  247. /* Linus sez that gcc can optimize the following correctly, we'll see if this
  248.  * holds on the Sparc as it does for the ALPHA.
  249.  */
  250.  
  251. #define find_first_zero_bit(addr, size) \
  252.         find_next_zero_bit((addr), (size), 0)
  253.  
  254. #ifndef __KERNEL__
  255.  
  256. extern __inline__ int set_le_bit(int nr, void *addr)
  257. {
  258.     int        mask;
  259.     unsigned char    *ADDR = (unsigned char *) addr;
  260.  
  261.     ADDR += nr >> 3;
  262.     mask = 1 << (nr & 0x07);
  263.     __asm__ __volatile__("
  264.     ldub    [%0], %%g3
  265.     or    %%g3, %2, %%g2
  266.     stb    %%g2, [%0]
  267.     and    %%g3, %2, %0
  268.     "
  269.     : "=&r" (ADDR)
  270.     : "0" (ADDR), "r" (mask)
  271.     : "g2", "g3");
  272.  
  273.     return (int) ADDR;
  274. }
  275.  
  276. extern __inline__ int clear_le_bit(int nr, void *addr)
  277. {
  278.     int        mask;
  279.     unsigned char    *ADDR = (unsigned char *) addr;
  280.  
  281.     ADDR += nr >> 3;
  282.     mask = 1 << (nr & 0x07);
  283.     __asm__ __volatile__("
  284.     ldub    [%0], %%g3
  285.     andn    %%g3, %2, %%g2
  286.     stb    %%g2, [%0]
  287.     and    %%g3, %2, %0
  288.     "
  289.     : "=&r" (ADDR)
  290.     : "0" (ADDR), "r" (mask)
  291.     : "g2", "g3");
  292.  
  293.     return (int) ADDR;
  294. }
  295.  
  296. #else /* __KERNEL__ */
  297.  
  298. /* Now for the ext2 filesystem bit operations and helper routines. */
  299.  
  300. extern __inline__ int set_le_bit(int nr,void * addr)
  301. {
  302.     register int mask asm("g2");
  303.     register unsigned char *ADDR asm("g1");
  304.  
  305.     ADDR = ((unsigned char *) addr) + (nr >> 3);
  306.     mask = 1 << (nr & 0x07);
  307.     __asm__ __volatile__("
  308.     mov    %%o7, %%g4
  309.     call    ___set_le_bit
  310.      add    %%o7, 8, %%o7
  311. "    : "=&r" (mask)
  312.     : "0" (mask), "r" (ADDR)
  313.     : "g3", "g4", "g5", "g7", "cc");
  314.  
  315.     return mask;
  316. }
  317.  
  318. extern __inline__ int clear_le_bit(int nr, void * addr)
  319. {
  320.     register int mask asm("g2");
  321.     register unsigned char *ADDR asm("g1");
  322.  
  323.     ADDR = ((unsigned char *) addr) + (nr >> 3);
  324.     mask = 1 << (nr & 0x07);
  325.     __asm__ __volatile__("
  326.     mov    %%o7, %%g4
  327.     call    ___clear_le_bit
  328.      add    %%o7, 8, %%o7
  329. "    : "=&r" (mask)
  330.     : "0" (mask), "r" (ADDR)
  331.     : "g3", "g4", "g5", "g7", "cc");
  332.  
  333.     return mask;
  334. }
  335.  
  336. #endif /* __KERNEL__ */
  337.  
  338. extern __inline__ int test_le_bit(int nr, __const__ void * addr)
  339. {
  340.     int            mask;
  341.     __const__ unsigned char    *ADDR = (__const__ unsigned char *) addr;
  342.  
  343.     ADDR += nr >> 3;
  344.     mask = 1 << (nr & 0x07);
  345.     return ((mask & *ADDR) != 0);
  346. }
  347.  
  348. #ifdef __KERNEL__
  349.  
  350. #define ext2_set_bit   set_le_bit
  351. #define ext2_clear_bit clear_le_bit
  352. #define ext2_test_bit  test_le_bit
  353.  
  354. #endif /* __KERNEL__ */
  355.  
  356. #define find_first_zero_le_bit(addr, size) \
  357.         find_next_zero_le_bit((addr), (size), 0)
  358.  
  359. extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
  360. {
  361.     unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
  362.     unsigned long result = offset & ~31UL;
  363.     unsigned long tmp;
  364.  
  365.     if (offset >= size)
  366.         return size;
  367.     size -= result;
  368.     offset &= 31UL;
  369.     if(offset) {
  370.         tmp = *(p++);
  371.         tmp |= __swab32(~0UL >> (32-offset));
  372.         if(size < 32)
  373.             goto found_first;
  374.         if(~tmp)
  375.             goto found_middle;
  376.         size -= 32;
  377.         result += 32;
  378.     }
  379.     while(size & ~31UL) {
  380.         if(~(tmp = *(p++)))
  381.             goto found_middle;
  382.         result += 32;
  383.         size -= 32;
  384.     }
  385.     if(!size)
  386.         return result;
  387.     tmp = *p;
  388.  
  389. found_first:
  390.     return result + ffz(__swab32(tmp) | (~0UL << size));
  391. found_middle:
  392.     return result + ffz(__swab32(tmp));
  393. }
  394.  
  395. #ifdef __KERNEL__
  396.  
  397. #define ext2_find_first_zero_bit     find_first_zero_le_bit
  398. #define ext2_find_next_zero_bit      find_next_zero_le_bit
  399.  
  400. /* Bitmap functions for the minix filesystem.  */
  401. #define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
  402. #define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
  403. #define minix_test_bit(nr,addr) test_bit(nr,addr)
  404. #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
  405.  
  406. #endif /* __KERNEL__ */
  407.  
  408. #endif /* defined(_SPARC_BITOPS_H) */
  409.